#ifndef NETLIB_BUFFER_H
#define NETLIB_BUFFER_H

// IO缓冲区类，使用LT模式
// 与poll兼容，不会漏掉事件的BUG，读写不必等待EAGAIN至少节省一次系统调用（read&write）

#include "copyable.h"
#include "StringPiece.h"
#include "Types.h"
#include "Endian.h"

#include <algorithm>
#include <vector>

#include <assert.h>
#include <string.h>

namespace netlib
{

namespace net
{

class Buffer : public netlib::copyable // IO缓冲区类
{
public:
    static const size_t kCheapPrepend = 8;      // 初始的预留空间的大小
    static const size_t kInitialSize = 1024;    // 初始化的缓冲区空间大小

    explicit Buffer(size_t initialSize = kInitialSize)
        : buffer_(kCheapPrepend + initialSize),
        readerIndex_(kCheapPrepend),
        writerIndex_(kCheapPrepend)
    {
        assert(readableBytes() == 0);
        assert(writableBytes() == initialSize);
        assert(prependableBytes() == kCheapPrepend);
    }

    void swap(Buffer& rhs) // 交换两个缓冲区
    {
        buffer_.swap(rhs.buffer_);
        std::swap(readerIndex_, rhs.readerIndex_);
        std::swap(writerIndex_, rhs.writerIndex_);
    }

    // 返回可读区的大小
    size_t readableBytes() const { return writerIndex_ - readerIndex_; }

    // 返回可写区的大小
    size_t writableBytes() const { return buffer_.size() - writerIndex_; }

    // 返回预留区的大小
    size_t prependableBytes() const { return readerIndex_; }

    // 返回读位置
    const char* peek() const { return begin() + readerIndex_; }

    // std::search(ForwardIt1 first, ForwardIt1 last,
    //              ForwardIt2 s_first, ForwardIt2 s_last)
    // 在迭代器[first,last)中，寻找子序列[s_first,s_last)首次出现的位置
    const char* findCRLF() const // 查找\r\n
    {
        const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2);
        return crlf == beginWrite() ? NULL : crlf;
    }

    // 从start处开始查找\r\n
    const char* findCRLF(const char* start) const
    {
        assert(peek() <= start);
        assert(start <= beginWrite());
        const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2);
        return crlf == beginWrite() ? NULL : crlf;
    }

    // 查找\n
    const char* findEOL() const
    {
        const void* eol = memchr(peek(), '\n', readableBytes());
        return static_cast<const char*>(eol);
    }

    // 从start处开始查找\n
    const char* findEOL(const char* start) const
    {
        assert(peek() <= start);
        assert(start <= beginWrite());
        const void* eol = memchr(start, '\n', beginWrite() - start);
        return static_cast<const char*>(eol);
    }

    void retrieve(size_t len) // 取出len长度的数据
    {
        assert(len <= readableBytes());
        if (len < readableBytes())
            readerIndex_ += len;
        else
            retrieveAll(); // 如果len大于总的可读长度，则取出所有可读数据，缓冲区清零
    }

    void retrieveUntil(const char* end) // 取出从可读到end区间的数据
    {
        assert(peek() <= end);
        assert(end <= beginWrite());
        retrieve(end - peek());
    }

    void retrieveInt64() { retrieve(sizeof(int64_t)); } // 取出8个字节

    void retrieveInt32() { retrieve(sizeof(int32_t)); } // 取出4个字节

    void retrieveInt16() { retrieve(sizeof(int16_t)); } // 取出2个字节

    void retrieveInt8() { retrieve(sizeof(int8_t)); } // 取出1个字节

    void retrieveAll() // 重置缓冲区，读、写位置重置
    {
        readerIndex_ = kCheapPrepend;
        writerIndex_ = kCheapPrepend;
    }

    // 取出所有的数据，并返回字符串，retrieveAsString的封装
    string retrieveAllAsString() { return retrieveAsString(readableBytes()); }

    // 取出len长度的数据，转化成字符串返回
    string retrieveAsString(size_t len)
    {
        assert(len <= readableBytes());
        string result(peek(), len);
        retrieve(len);
        return result;
    }

    // 返回所有数据的StringPiece形式
    StringPiece toStringPiece() const
    { return StringPiece(peek(), static_cast<int>(readableBytes())); }

    // 向缓冲区添加数据，传入StringPiece
    void append(const StringPiece& str) { append(str.data(), str.size()); }

    // 向缓冲区添加数据，传入char*、len长度
    void append(const char* data, size_t len)
    {
        ensureWritableBytes(len); // 比较len与可写长度，不足则扩容
        std::copy(data, data+len, beginWrite()); // 向缓冲区加入数据
        hasWritten(len); // 更新写位置
    }

    // 向缓冲区添加数据，传入void*、len长度
    void append(const void* data, size_t len)
    { append(static_cast<const char*>(data), len); } // 转化成char*再添加

    // 比较len与可写长度，不足则扩容
    void ensureWritableBytes(size_t len)
    {
        if (writableBytes() < len)
            makeSpace(len); // 空间不足，扩充空间
        assert(writableBytes() >= len);
    }

    // 返回从缓冲区起始位置到可写长度的偏移指针char*
    char* beginWrite() { return begin() + writerIndex_; }

    // 返回从缓冲区起始位置到可写长度的偏移指针const char*
    const char* beginWrite() const { return begin() + writerIndex_; }

    void hasWritten(size_t len) // 更新写位置
    {
        assert(len <= writableBytes());
        writerIndex_ += len;
    }

    void unwrite(size_t len) // 缓冲区数据尾端取出len个字节
    {
        assert(len <= readableBytes());
        writerIndex_ -= len;
    }

    void appendInt64(int64_t x) // 添加64位整数
    {
        int64_t be64 = sockets::hostToNetwork64(x); // 转换成网络字节序存储
        append(&be64, sizeof be64);
    }

    void appendInt32(int32_t x) // 添加32位整数
    {
        int32_t be32 = sockets::hostToNetwork32(x); // 转换成网络字节序存储
        append(&be32, sizeof be32);
    }

    void appendInt16(int16_t x) // 添加16位整数
    {
        int16_t be16 = sockets::hostToNetwork16(x); // 转换成网络字节序存储
        append(&be16, sizeof be16);
    }

    void appendInt8(int8_t x) { append(&x, sizeof x); } // 添加8位整数，一个字节不转换

    int64_t readInt64() // 读取8个字节
    {
        int64_t result = peekInt64();
        retrieveInt64();
        return result;
    }

    int32_t readInt32() // 读取4个字节
    {
        int32_t result = peekInt32();
        retrieveInt32();
        return result;
    }

    int16_t readInt16() // 读取2个字节
    {
        int16_t result = peekInt16();
        retrieveInt16();
        return result;
    }

    int8_t readInt8() // 读取1个字节
    {
        int8_t result = peekInt8();
        retrieveInt8();
        return result;
    }

    int64_t peekInt64() const // 从缓冲区取出8个字节的数据
    {
        assert(readableBytes() >= sizeof(int64_t));
        int64_t be64 = 0;
        ::memcpy(&be64, peek(), sizeof be64);
        return sockets::networkToHost64(be64); // 转成原来的主机字节序
    }

    int32_t peekInt32() const // 从缓冲区取出4个字节的数据
    {
        assert(readableBytes() >= sizeof(int32_t));
        int32_t be32 = 0;
        ::memcpy(&be32, peek(), sizeof be32);
        return sockets::networkToHost32(be32); // 转成原来的主机字节序
    }

    int16_t peekInt16() const // 从缓冲区取出2个字节的数据
    {
        assert(readableBytes() >= sizeof(int16_t));
        int16_t be16 = 0;
        ::memcpy(&be16, peek(), sizeof be16);
        return sockets::networkToHost16(be16); // 转成原来的主机字节序
    }

    int8_t peekInt8() const // 从缓冲区取出1个字节的数据
    {
        assert(readableBytes() >= sizeof(int8_t));
        int8_t x = *peek();
        return x;
    }

    void prependInt64(int64_t x) // 在缓冲区头插8个字节数据
    {
        int64_t be64 = sockets::hostToNetwork64(x);
        prepend(&be64, sizeof be64);
    }

    void prependInt32(int32_t x) // 在缓冲区头插4个字节数据
    {
        int32_t be32 = sockets::hostToNetwork32(x);
        prepend(&be32, sizeof be32);
    }

    void prependInt16(int16_t x) // 在缓冲区头插2个字节数据
    {
        int16_t be16 = sockets::hostToNetwork16(x);
        prepend(&be16, sizeof be16);
    }

    // 在缓冲区头插1个字节数据
    void prependInt8(int8_t x) { prepend(&x, sizeof x); }

    // 缓冲区读位置头插入长度位len的数据data
    void prepend(const void* data, size_t len)
    {
        assert(len <= prependableBytes());
        readerIndex_ -= len;
        const char* d = static_cast<const char*>(data);
        std::copy(d, d+len, begin()+readerIndex_);
    }

    void shrink(size_t reserve) // 伸缩空间，保留reserve个字节的空间，其他的释放掉
    {
        Buffer other;
        other.ensureWritableBytes(readableBytes()+reserve);
        other.append(toStringPiece());
        swap(other);
    }

    size_t internalCapacity() const { return buffer_.capacity(); }

    // 从套接字中读取数据，保存到缓冲区中
    ssize_t readFd(int fd, int* savedErrno);

private:

    char* begin() { return &*buffer_.begin(); } // 返回缓冲区的起始地址char*

    // 返回const char*缓冲区的起始地址
    const char* begin() const { return &*buffer_.begin(); }

    void makeSpace(size_t len) // 缓冲区扩容
    {
        if (writableBytes() + prependableBytes() < len + kCheapPrepend)
            buffer_.resize(writerIndex_+len);
        else // 可写长度加预留长度>=len+8，不用扩容，只需要向前搬移，让读位置复位
        {
            assert(kCheapPrepend < readerIndex_);
            size_t readable = readableBytes();
            std::copy(begin()+readerIndex_, begin()+writerIndex_, begin()+kCheapPrepend);
            readerIndex_ = kCheapPrepend;
            writerIndex_ = readerIndex_ + readable;
            assert(readable == readableBytes());
        }
    }

private:
    std::vector<char> buffer_;      // 可扩容的连续的缓冲区向量
    size_t readerIndex_;            // 读位置
    size_t writerIndex_;            // 写位置

    static const char kCRLF[];      // 查找标志\r\n

}; // class Buffer end

} // namespace net end

} // namespace netlib end

#endif